package testJdk.net.quota;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.BufferUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.symmetric.AES;
import cn.hutool.json.JSONUtil;
import cn.hutool.socket.nio.NioClient;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.io.Serializable;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.List;

/**
 * 风险管控测试
 *
 * @author：Administrator
 * @date：2023/9/15 8:47
 */
public class QuotaDataTest {

    private static final String APP_ID = "315168ec596d4d102302488414801470";
    private static final String SECRET_KEY = "7520fde709b67dcb";
    private static final String DATA_SERVICE_ID = "69b1e2606a4d8bf732ebd8e2a3836b0d";
    private static final String ALARM_SERVICE_ID = "ee625a257c5e7e7e5727136e144d6f2f";
    private static final String IV = "0000000000000000";

    /**
     * 企业编码
     */
    private static final String ENTERPRISE_ID = "42098000";

    /**
     * 网关编码
     */
    private static final String GATEWAY_ID = "4209800001";

    private static final AES aes = new AES(Mode.CBC, Padding.PKCS5Padding, SECRET_KEY.getBytes(), IV.getBytes());

    public static void main(String[] args) {
        new QuotaDataTest().sendRealData2();
    }

    /**
     * 实时数据
     */
    public void sendRealData2() {
        String data = "{\"appId\":\"315168ec596d4d102302488414801470\",\"serviceId\":\"69b1e2606a4d8bf732ebd8e2a3836b0d\",\"dataId\":\"c4470949-e126-4c41-b409-eb2c70059efb\",\"data\":\"XrjcSaDkBNqqPHqHae+zgRYiesXMA0jUti8BjLIxPgTwCsWEgZUghAQlIDWgX5BFduU0/Knv2spYJleebly4QKA95Ni6yJ/CP1u7xndbsTX9kanyF4O6QaucZHM+hoqmsLsbfbomoozaONvaBCmNCEfZiNuJUc0BdSzXSB2lAXFagGTQNTxWeSHuOgEtpCuxoc3/0VCS7d3XSAiC7b+7tWRcTPeUTxmPn0OyTxSqVTlgN6pSDX1IS82t18v3MHNc/b5Lly1CuBzX4RAvWuQPKSPKZx90kbXXGFvZpj5Wzd02E3sTJZ3mdRoe2mKEPaCnQXQf6qY5Ty6o5jSuJNjuA9goO9tpYoOPQu4coOYXDLO2k+zeuvfe/oY9R/JBrpg/jCtfg2z9bqDWLd3FSiTF61O1SX9REdLnOb32FiVOt1kkLDnZ4bclLcN2eRw4PBh/3Dpr0ELP4MCzmib1dbhjT6q3muF2nPqgOHvJrt8dSg/OoYqGBtrze1SdFTKNR0vLm1HMC/f47Ow1ryBW20KToAOkElt6JB6dzcJN+gO+BTz7+rmJlwISf/wEFV0kGXQ/\"}@@";

        NioClient client = new NioClient("127.0.0.1", 9088);
        client.setChannelHandler((sc)->{
            ByteBuffer readBuffer = ByteBuffer.allocate(4096);
            //从channel读数据到缓冲区
            int readBytes = sc.read(readBuffer);
            if (readBytes > 0) {
                //Flips this buffer.  The limit is set to the current position and then
                // the position is set to zero，就是表示要从起始位置开始读取数据
                readBuffer.flip();
                //returns the number of elements between the current position and the  limit.
                // 要读取的字节长度
                byte[] bytes = new byte[readBuffer.remaining()];
                //将缓冲区的数据读到bytes数组
                readBuffer.get(bytes);
                String body = StrUtil.utf8Str(bytes);
                Console.log("[{}]: {}", sc.getRemoteAddress(), body);
            } else if (readBytes < 0) {
                sc.close();
            }
        });
        client.listen();
        client.write(BufferUtil.createUtf8(data));
        client.close();
    }

    /**
     * 实时数据
     */
    public void sendRealData() {
        RealtimeMsg realtimeMsg = createRealtimeMsg(Collections.singletonList(new QuotaVo("420900001001QT1", 0d)));
        ReportReq reportReq = new ReportReq()
                .setAppId(APP_ID)
                .setServiceId(DATA_SERVICE_ID)
                .setDataId(realtimeMsg.getDataId())
                .setEnterpriseId(ENTERPRISE_ID)
                .setGatewayId(GATEWAY_ID)
                .setBaseMsg(realtimeMsg);

        reportReq.setData(aes.encryptBase64(JSONUtil.toJsonStr(reportReq.getBaseMsg())));
        String data = JSONUtil.toJsonStr(reportReq).concat("@@");

        NioClient client = new NioClient("221.233.192.80", 8091);
        client.setChannelHandler((sc)->{
            ByteBuffer readBuffer = ByteBuffer.allocate(1024);
            //从channel读数据到缓冲区
            int readBytes = sc.read(readBuffer);
            if (readBytes > 0) {
                //Flips this buffer.  The limit is set to the current position and then
                // the position is set to zero，就是表示要从起始位置开始读取数据
                readBuffer.flip();
                //returns the number of elements between the current position and the  limit.
                // 要读取的字节长度
                byte[] bytes = new byte[readBuffer.remaining()];
                //将缓冲区的数据读到bytes数组
                readBuffer.get(bytes);
                String body = StrUtil.utf8Str(bytes);
                Console.log("[{}]: {}", sc.getRemoteAddress(), body);
            } else if (readBytes < 0) {
                sc.close();
            }
        });
        client.listen();
        client.write(BufferUtil.createUtf8(data));
        client.close();
    }


    /**
     * 创建报警数据
     * @param list 报警数据集合
     * @return
     */
    public AlarmMsg createAlarmMsg( List<AlarmVo> list) {
        AlarmMsg msg = new AlarmMsg();
        msg.setDataId(IdUtil.simpleUUID());
        msg.setEnterpriseId(ENTERPRISE_ID);
        msg.setGatewayId(GATEWAY_ID);
        msg.setCollectTime(DateUtil.format(DateUtil.date(), DatePattern.PURE_DATETIME_PATTERN));
        msg.setReportType("report");
        msg.setConnectDataSource(true);
        msg.setAlarms(list);
        return msg;
    }

    /**
     * 创建报警数据
     * @param list 实时数据
     * @return 实时数据
     */
    public RealtimeMsg createRealtimeMsg(List<QuotaVo> list) {
        RealtimeMsg msg = new RealtimeMsg();
        msg.setDataId(IdUtil.simpleUUID());
        msg.setEnterpriseId(ENTERPRISE_ID);
        msg.setGatewayId(GATEWAY_ID);
        msg.setReportType("report");
        msg.setCollectTime(DateUtil.format(DateUtil.date(), DatePattern.PURE_DATETIME_PATTERN));
        msg.setDataType("energy_data");
        msg.setConnectDataSource(true);
        msg.setDatas(list);
        return msg;
    }


    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    class RealtimeMsg extends BaseMsg {

        /**
         * 指标数据集合
         */
        private List<QuotaVo> datas;

    }

    /**
     * @author luobaol
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    class QuotaVo {
        /**
         * 指标编码
         */
        private String quotaId;

        /**
         * 指标当前采集值
         */
        private Double value;

    }


    @Data
    class BaseMsg implements Serializable {

        /**
         * 调用者定义的数据包ID，同一个数据包必须具有相同且全局唯一的ID。服务使用本字段数据判断是否传递了重复的包。建议使用UUID
         */
        private String dataId;

        /**
         * 实时数据：energy_data,报警数据：alarm
         */
        private String dataType;

        /**
         * 企业编码
         */
        private String enterpriseId;

        /**
         * 网关编码
         */
        private String gatewayId;

        /**
         * 时间戳，格式YYYYMMDDHHmmss
         */
        private String collectTime;

        /**
         * 数据源连通性，true表示数据源连通正常，数据有效；false表示数据源连通异常，数据无效
         */
        @JsonFormat
        private boolean isConnectDataSource;

        /**
         * 报文类型，report表示实时报文；continues表示当前传输的为历史报文
         */
        private String reportType;
    }


    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    class AlarmMsg extends BaseMsg {

        private List<AlarmVo> alarms;
    }

    @Data
    @Accessors(chain = true)
    class AlarmVo {

        /**
         * 指标编码
         */
        private String quotaId;

        /**
         * 指标当前采集值
         */
        private Double value;

        /**
         * 报警类型：
         * alarm hi:alarm表示超上限报警；
         * alarm hh:alarm表示超上上限报警；
         * alarm lo:alarm表示超下限报警;
         * alarm ll:alarm表示超下下限报警;
         * normal:alarm表示消警;
         * alarmsignal表示变化报警，即开关量报警;
         */
        private String alarmType;

        /**
         * 当前报警/消警阈值。当为变化报警时，阈值为上次报警/消警状态，即当前采集值为1，阈值则为0
         */
        private Double threshold;

        /**
         * 报警时间戳，格式YYYYMMDDHHmmss
         */
        private String alarmTime;
    }

    /**
     * <pre>
     * 实例
     * {
     * 	"enterpriseId": "123456",
     * 	"dataId": "0a5f75eed2e94149bd88fe6aaa410d4c",
     * 	"data": "【加密前格式见下文3.7和3.8，使用AES加密后转为base64的字符串作为此处的内容】"
     * }@@
     * </pre>
     * 省平台数据上报报文体
     */
    @Data
    @Accessors(chain = true)
    class ReportReq implements Serializable {

        private static final long serialVersionUID = -2577707401136472809L;

        /**
         * appId
         */
        private String appId;
        /**
         * serviceId
         */
        private String serviceId;
        /**
         * 企业编码
         */
        private String enterpriseId;
        /**
         * 数据包id
         */
        private String dataId;

        /**
         * 加密数据, 使用AES加密后转为base64的字符串作为此处的内容
         */
        private String data;


        /**
         * 网关编码
         */
        @JsonFormat
        private String gatewayId;

        /**
         * 加密前数据
         */
        @JsonFormat
        private BaseMsg baseMsg;

        @Override
        public String toString() {
            return "TcpRequest{enterpriseId=" + enterpriseId + ", dataId=" + dataId + ", data=" + data + "}";
        }
    }
}
